package org.youyee.game.managers
{
	import org.youyee.game.displayArea.Area;
	import org.youyee.game.event.AnimationEvent;
	import org.youyee.game.event.MoveEvent;
	import org.youyee.game.object.MapObject;
	import org.youyee.game.pathFinding.PathCalculator;
	import org.youyee.game.pathFinding.PathNode;
	import org.youyee.game.utils.PositionCalculator;
	
	import flash.display.DisplayObject;
	import flash.utils.Dictionary;

	/**
	 * 场景上的物体移动管理器 (允许中途变更路径，管理器会自动让物体的路径变更显得更加自然)
	 * @author youyeelu
	 * 
	 */	
	public class MapObjectMoveManager
	{
		private var _pathCalculator:PathCalculator;
		private var _queryCache:Object;
		private var _objects:Dictionary;
		private var _area:Area;
		
		/**
		 * 构造函数 
		 * @param area 管理的区域
		 * 
		 */		
		public function MapObjectMoveManager(area:Area)
		{
			this._queryCache = {};
			this._area = area;
			this._objects = new Dictionary();
			addListener();
		}
		
		private function addListener():void
		{
			this._area.addEventListener(MoveEvent.GOTO_PATHNODE, handleGotoPathNode);
			this._area.addEventListener(MoveEvent.ABORT_MOVE, handleAbort);
		}
		
		private function removeListener():void
		{
			if (this._area)
			{
				this._area.removeEventListener(MoveEvent.GOTO_PATHNODE, handleGotoPathNode);
				this._area.removeEventListener(MoveEvent.ABORT_MOVE, handleAbort);
			}
		}
		
		private function handleGotoPathNode(e:MoveEvent):void
		{
			var moveItem:MoveParameter = e.data as MoveParameter;
			
			if (moveItem)
			{
				addMoveItem(moveItem);
			}
		}
		
		private function handleAbort(e:MoveEvent):void
		{
			var object:MapObject = e.target as MapObject;
			
			if (object && this._objects[object])
			{
				var item:MoveParameter = this._objects[object] as MoveParameter;
				item.destroy();
				delete _objects[object];
			}
		}
		
		/**
		 * 添加一个移动项目 
		 * @param moveItem 移动项目
		 * 
		 */		
		public function addMoveItem(moveItem:MoveParameter):void
		{
			var path:Array = getPath(moveItem.object.pathNode, moveItem.targetPathNode);
			
			if (path)
			{
				moveItem.path = path;
				moveItem.index = 0;
				
				if (this._objects[moveItem.object])
				{
					var m:MoveParameter = this._objects[moveItem.object] as MoveParameter;
					if (path[1] == m.object.pathNode)
					{
						moveItem.index = 1;
					}
					
					m.destroy();
					this._objects[moveItem.object] = moveItem;
				}
				else
				{
					this._objects[moveItem.object] = moveItem;
					makeItemMove(moveItem);
				}
			}
			else
			{
				moveItem.object.dispatchEvent(new MoveEvent(MoveEvent.NO_PATH));
				moveItem.destroy();
			}
		}
		
		private function handleObjectOnPosition(object:DisplayObject):void
		{
			if (!_objects)
			{
				return ;
			}
			
			var obj:MapObject = object as MapObject;
			
			if (obj && this._objects[obj])
			{
				var item:MoveParameter = this._objects[obj] as MoveParameter;
				
				obj.pathNode = item.path[item.index];
				obj.dispatchEvent(new MoveEvent(MoveEvent.ON_PATHNODE, this._objects[obj]));
				
				if (item.onPathNodeHandler is Function)
				{
					item.onPathNodeHandler(item);
				}
				
				if (item.index < item.path.length - 1)
				{
					makeItemMove(item);
				}
				else
				{
					if (item.arrivedHandler is Function)
					{
						item.arrivedHandler(item)
					}
					
					obj.dispatchEvent(new MoveEvent(MoveEvent.ARRIVED, this._objects[obj]));
					removeMoveItemByObject(item.object);
				}
			}
		}
		
		private function makeItemMove(moveItem:MoveParameter):void
		{
			var param:AnimationParameters = new AnimationParameters(
				moveItem.object, 
				PositionCalculator.getPositionByPathNode(moveItem.path[++moveItem.index]),
				handleObjectOnPosition
			);
			
			if (moveItem.prepareToHandler is Function)
			{
				moveItem.prepareToHandler(moveItem);
			}
			
			moveItem.object.dispatchEvent(new AnimationEvent(AnimationEvent.REQUEST_MOVETO, param));
		}
		
		/**
		 * 获取路径 
		 * @param startNode 开始节点
		 * @param targetNode 结束节点
		 * @param useCache 是否使用缓存
		 * @return 寻找到的路径
		 * 
		 */		
		public function getPath(startNode:PathNode, targetNode:PathNode, useCache:Boolean=true):Array
		{
			_pathCalculator = _pathCalculator || new PathCalculator();
			var key:String = startNode.key + "_" + targetNode.key;
			
			if (this._queryCache[key] && useCache)
			{
				return this._queryCache[key] as Array;
			}
			
			var path:Array = _pathCalculator.calculatePath(startNode, targetNode, _area.pathMap, true);
			
			if (path)
			{
				this._queryCache[key] = path;
			}
			
			return path;
		}
		
		/**
		 * 通过一个物品创建一个移动项目 
		 * @param object 移动的物体
		 * @param targetPathNode 目标的位置
		 * @param onPathNodehandler 每行走一个节点的回调
		 * @param arrivedHandler 到达终点后的回调
		 * 
		 */		
		public function addMovItemByObject(object:MapObject, targetPathNode:PathNode, onPathNodehandler:Function=null, arrivedHandler:Function=null):void
		{
			var moveItem:MoveParameter = new MoveParameter(object, targetPathNode, onPathNodehandler, arrivedHandler);
			addMoveItem(moveItem);
		}
		
		/**
		 * 通过物品移除一个移动项目 
		 * @param object 移动的物体
		 * 
		 */		
		public function removeMoveItemByObject(object:MapObject):void
		{
			var item:MoveParameter = this._objects[object] as MoveParameter;
			
			if (item)
			{
				item.destroy();
				delete this._objects[object];
			}
		}
		
		/**
		 * 销毁管理器 
		 * 
		 */		
		public function destroy():void
		{
			var mi:MoveParameter;
			
			for (var i:* in _objects)
			{
				mi = _objects[i] as MoveParameter;
				mi.destroy();
			}
			
			_objects = null;
			removeListener();
			this._area = null;
			this._queryCache = null;
			this._pathCalculator = null;
		}
	}
}